"""Helper functions

Consists of functions to typically be used within templates, but also
available to Controllers. This module is available to templates as 'h'.
"""
# Import helpers as desired, or define your own, ie:
#from webhelpers.html.tags import checkbox, password

import base64
import hashlib
import logging
import re
import time
import os.path
import pickle

from pylons import config, request, response, session
from serverengine.model.meta import Session, TUser, table_users

log = logging.getLogger(__name__)
sessionLength = 7200 # 2-hour session
adminSessionLength = 0.25 # the multiply of sessionLength

def serialize(target):
    return base64.b32encode(base64.b64encode(pickle.dumps(target)))

def cache_user_object(user_object):
    ''' Cache the information about the user for data recovery. '''
    user_object_location = "%s/%s.userobject" % (config['user_directory_base'], user_object.username)
    if os.path.exists(user_object_location):
        os.unlink(user_object_location)
    fp = open(user_object_location, "w")
    fp.write(serialize(user_object))
    fp.close()

def consealEmailAddress(emailAddress):
    return re.sub("\@", " at ", emailAddress)

# Candidate methods for Yotsuba 2
def unescape(string):
    """Unescape unicode character (from HTML entities)"""
    unicodeCharacters = re.findall("&#([0-9]+);", string)
    for uc in unicodeCharacters:
        string = re.sub("&#%s;" % uc, unichr(int(uc)), string)
    return string

# Security

def encodePassword(passwordText):
    try:
        return "%s%s" % (hashlib.sha1(passwordText).hexdigest(), hashlib.md5(passwordText).hexdigest())
    except:
        return ""
    
# Authorization

def addUser(username, password, realname, email):
    """
    Create an account
    """
    returnedMessage = None
    
    password = password
    realname = realname
    
    userdb = Session.query(TUser)
    userByID = userdb.filter_by(username = username).first()
    userByEmail = userdb.filter_by(email = email).first()
    
    if userByID:
        log.info('"%s" already exists' % username)
        returnedMessage = 'User already exists';
    elif userByEmail:
        log.info('"%s" already in used' % email)
        returnedMessage = 'E-mail adress already in used';
    
    
    if not returnedMessage:
        try:
            # Then, insert
            ins = table_users.insert().values(
                username = username,
                password = encodePassword(password),
                realname = realname,
                email = email
            )
            Session.execute(ins)
            
            # Cache the object
            new_user = userdb.filter_by(email = email).first()
            cache_user_object(new_user)
        except:
            returnedMessage = "Couldn't add the user at this time"
    
    return returnedMessage

def grantAccessTo(authID, password, isAdminAccess = False):
    """
    Grant the access to the user
    """
    global sessionLength
    userdb = Session.query(TUser)
    password = encodePassword(password)
    
    log.debug("Accessing as %s (%s)" % (authID, password))
    
    ret = None
    if isAdminAccess:
        log.debug("Admin Access")
        if config['admin_username'] == authID and config['admin_password'] == password:
            log.debug("Gained Admin Access")
            ret = TUser(0, authID, 'no-password', 'System Administrator', 'no-reply')
            ret = ret.dict()
        else:
            log.debug("Failed to get Admin Access")
    else:
        log.debug("Normal Access")
        try:
            firstTry = userdb.filter_by(username = authID, password = password).first()
            if firstTry:
                ret = firstTry
        except:
            log.critical("Error occurred in the first try")
        
        try:
            secondTry = userdb.filter_by(email = authID, password = password).first()
            if secondTry:
                ret = secondTry
        except:
            log.critical("Error occurred in the second try")
        
        if ret is not None:
            ret = ret.dict()
    
    if ret is not None:
        session['user'] = ret
        session.save()
        extendSessionLength(isAdminAccess)
    
    return ret

def denyAccess():
    try:
        del session['user']
        del session['length']
        session.save()
        return True
    except:
        log.critical("Error while removing session ID")
        return False


def hasAuthorization(isAdminAccess = False):
    ret = 'user' in session
    if ret:
        try:
            ret = session['user']['username']
            if isAdminAccess and not ret == config['admin_username']:
                ret = False
        except:
            log.error("This session is not valid")
            del session['user']
            session.save()
            ret = False
    if ret:
        ret = session['length'] > time.time()
    if ret:
        extendSessionLength(isAdminAccess)
    return ret

def extendSessionLength(isAdminAccess = False):
    if isAdminAccess:
        session['length'] = time.time() + (sessionLength * adminSessionLength)
    else:
        session['length'] = time.time() + sessionLength
    session.save()